package pt.uc.dei.mse.eai.xmlBuilder;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.URISyntaxException;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;

import org.apache.commons.io.FileUtils;
import org.xml.sax.SAXException;


import pt.uc.dei.mse.eai.model.dataModel.Cinema;

public class XMLBuilder {
	
	/**
	 * This defines the style sheet header to be included in the XML preamble
	 */
	private final String STYLESHEET =  "<?xml-" +
	"stylesheet type=\"text/xsl\" href=\"Cinecartaz.xsl\" ?>";
	
	/**
	 * This method produces XML and/or HTML files with the information about the movies
	 * 
	 * @param cinema The base object containing the information about the movies
	 * @param outFilePath The output file complete name (including path)
	 * @param genHTML A flag indicating if HTML is to be generated also
	 * @return The name of the generated file
	 * 
	 * @throws SAXException
	 * @throws JAXBException
	 * @throws TransformerException
	 * @throws IOException
	 * @throws URISyntaxException
	 */
	public String createXML(Cinema cinema, String outFilePath, boolean genHTML)
			throws SAXException, JAXBException, TransformerException, IOException, URISyntaxException {

		
		// Build xml filename
		
		String xmlFile = new String(outFilePath);
		
		if(!xmlFile.endsWith(".xml")) {
			xmlFile = outFilePath.concat(".xml");	
		}
		
		// Creating the output stream to write the XML file, using UTF8 encoding
		
		FileOutputStream fos = new FileOutputStream(xmlFile);
		Writer out = new OutputStreamWriter(fos, "UTF8");		
		
		// Instantiate the schema to validate, at runtime, the XML before actually writing to the file
		
		SchemaFactory schemaFactory = SchemaFactory
				.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
		Schema schema = schemaFactory.newSchema(
				new File(
						ClassLoader.getSystemResource("resources/Cinecartaz.xsd").getFile()));

		// Creation of the JAXB context
		
		JAXBContext jc = JAXBContext
				.newInstance("pt.uc.dei.mse.eai.model.dataModel");

		Marshaller m = jc.createMarshaller();
		
		// Configures the marshaller to generated formatted XML
		
		m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
		
		// Configures the marshaller to add the stylesheet header to the preamble
		// only if the output was XML. In this case, it is necessary so the browser can display the XML properly.
		// If selected output was HTML, then the stylesheet is applied programatically and therefore
		// there is no need to bind the XML with a particular stylesheet
		
		if(!genHTML) {
			m.setProperty("com.sun.xml.internal.bind.xmlHeaders", STYLESHEET);
		}
		// Setting the schema into the marshaller
		m.setSchema(schema);
        m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
        
        // Configures the marshaller to generated XML headers
        
        m.setProperty(Marshaller.JAXB_FRAGMENT, false);

        // Write the XML file
        
		m.marshal(cinema, out);
		
		out.close();
		
		// Prints the XML also in the standard out
		
		m.marshal(cinema, System.out);
		
		
		// Copy the XSL file to the same directory as the generated XML file, since it is referenced
		// in the XML header
		
		copyFile(new File(ClassLoader.getSystemResource("resources/Cinecartaz.xsl").getFile()), 
				new File(xmlFile).getParentFile());
		
		// Copy the image used in the HTML
		copyFile(new File(ClassLoader.getSystemResource("resources/iPadBackgroundTexture-grey.png").getFile()), 
				new File(xmlFile).getParentFile());
		
		String htmlOut = null ; 

		if(genHTML) {
			 htmlOut = generateHTML(xmlFile, outFilePath);

		}
		
		
		return (genHTML) ? htmlOut : xmlFile;

	}
	
	/**
	 * Applies the XSL style sheet to the XML generating an HTML file
	 * @param xmlFile The XML file to use
	 * @param outFile The name of the file specified by the usere
	 * @return The name of the HTML file generated
	 * @throws TransformerException
	 * @throws URISyntaxException
	 */
	private String generateHTML(String xmlFile, String outFile) throws TransformerException, URISyntaxException {
		
		String newFile = new String(outFile);
		
		if(!outFile.endsWith(".html")) {
			newFile = outFile.concat(".html");	
		}
			
		TransformerFactory tFactory = TransformerFactory.newInstance();
			
		Transformer trans;

		trans = tFactory.newTransformer(new StreamSource(new File( ClassLoader.getSystemResource("resources/Cinecartaz.xsl").getFile()) ));
			
		trans.transform(new StreamSource( xmlFile ), new StreamResult( newFile ) );
		
			
		return newFile;
			
	}
	
	
	private void copyFile(File fileOri, File fileDest) throws IOException {
		

		if(fileDest == null) {
			
			fileDest = new File(".");
		}
		
		FileUtils.copyFileToDirectory(fileOri, fileDest, true);
	
		
	}
}
